﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.DependencyInjection;
using System.Text.Json.Nodes;
using System.Text.RegularExpressions;
using XYS.Core.Models;
using XYS.Core.Util;
using XYS.Service.Core.Attributes;

namespace XYS.Core.Api.Middlewares
{
    /// <summary>
    /// 响应数据格式统一
    /// </summary>
    public class ResponseModelHandle : IHttpStreamHandle
    {

        /// <summary>
        /// 优先级，数字越大 越早处理
        /// 小于0 则不处理
        /// </summary>
        public int PriorityLevel => 50;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="scope"></param>
        /// <param name="httpContext"></param>
        /// <param name="resqustBody"></param>
        /// <param name="newResqustBody"></param>
        /// <returns></returns>
        public object Invoke(IServiceScope scope, HttpContext httpContext, string resqustBody, out string newResqustBody)
        {
            newResqustBody = resqustBody;
            return null;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="scope"></param>
        /// <param name="httpContext"></param>
        /// <param name="responseBody"></param>
        /// <param name="invokeResult"></param>
        /// <returns></returns>
        public string Nexted(IServiceScope scope, HttpContext httpContext, string responseBody, object invokeResult)
        {
            if (httpContext != null && httpContext.Response.StatusCode >= 200 && httpContext.Response.StatusCode <= 299)
            {
                var endpoint = httpContext.Features.Get<IEndpointFeature>()?.Endpoint;
                if (endpoint?.Metadata.GetMetadata<ResultModelIgnoreAttribute>() == null
                    && !httpContext.Request.Path.Value.Contains(".", StringComparison.CurrentCulture)
                    && !GlobalCoreSetting.FormatRequestsIgnore.Any(x => Regex.IsMatch(httpContext.Request.Path.Value, "^" + Regex.Escape(x).Replace("\\*", ".*") + "$"))
                    )
                    return ToResultModelJson(responseBody);//自动判断是否需要 增加 ResultModel 对象
            }
            return responseBody;
        }


        /// <summary>
        /// 自动判断是否需要 增加 ResultModel 对象
        /// </summary>
        /// <param name="responesInfo"></param>
        /// <returns></returns>
        private static string ToResultModelJson(string responesInfo)
        {
            if (!string.IsNullOrWhiteSpace(responesInfo))
            {
                bool isResultModel = false;
                if (responesInfo.Contains("statusCode"))
                {
                    try
                    {
                        var jsonNode = JsonNode.Parse(responesInfo);

                        var map = responesInfo.ToObject<Dictionary<string, object>>();
                        if (map.Count >= 2)
                        {
                            if (map.ContainsKey("succeeded") && map.ContainsKey("statusCode"))
                            {
                                isResultModel = map.Count < 3 || (map.ContainsKey("data") || map.ContainsKey("result") || map.ContainsKey("error"));
                            }
                        }
                    }
                    catch { }
                }
                //如果不是 ResultModel 则给返回结果嵌套一层 ResultModel
                if (!isResultModel)
                {
                    try
                    {
                        //嵌套ResultModel
                        string result = $"{{\"data\":{responesInfo},\"succeeded\":true,\"statusCode\":200}}";
                        result.ToObject<object>();
                        return result;
                    }
                    catch
                    {
                        //嵌套ResultModel
                        return ResultModel<string>.Success(responesInfo).ToJson();
                    }
                }
                return responesInfo;
            }
            else
            {
                return ResultModel.Success.ToJson();
            }
        }



        /// <summary>
        /// 
        /// </summary>
        /// <param name="scope"></param>
        /// <param name="httpContext"></param>
        /// <param name="nextedResult"></param>
        public void ProEnd(IServiceScope scope, HttpContext httpContext, object nextedResult)
        {
        }
    }
}
